import io
import logging
from django.contrib.auth.models import User
from django_redis import get_redis_connection
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
# Create your views here.
from rest_framework_simplejwt.views import TokenObtainSlidingView
from rest_framework.viewsets import ModelViewSet, GenericViewSet, ReadOnlyModelViewSet
from rest_framework.mixins import *
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import action
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from fdfs_client.client import Fdfs_client, get_tracker_conf

from config.dbs.redisconfig import LOGIN_VERIFY_CODE_TEMPLATE, EXPIRE_TIME
from config.fastdfs.config import FASTDFS_SERVER_DOMAIN
from .serializers import *
from utils.verifyUtil import ImageVerify
from utils.customPermissions import *

# 导入日志器
logger = logging.getLogger(__name__)

client_conf = get_tracker_conf('config/fastdfs/client.conf')
client = Fdfs_client(client_conf)


class MyTokenView(TokenObtainSlidingView):
    serializer_class = MyTokenSerializer


class ImageVerifyView(View):  # 不需要mysql所以不用ModelViewSet
    def get(self, request, uuid):
        """
        获取图形验证码
        :param request:
        :return:
        """
        imgVerify = ImageVerify()
        img, code = imgVerify.image_code()

        # 图片以二进制形式进行传输
        # 创建一个字节流管道
        bytes_box = io.BytesIO()
        # 将图片以png格式保存到管道
        img.save(bytes_box, format='PNG')
        # 从字节流管道获取到的二进制图片
        image_bytes = bytes_box.getvalue()

        # code保存到redis数据库
        cache = get_redis_connection(alias='verify_codes')
        cache.set(LOGIN_VERIFY_CODE_TEMPLATE % uuid, code, EXPIRE_TIME)  # key value

        return HttpResponse(image_bytes, content_type='image/png')


class UserViewSet(RetrieveModelMixin, GenericViewSet):
    """
    django views.View
    drf ViewSet
        GenericViewSet+Mixin
        ModelViewSet
    """
    queryset = User.objects.filter(is_active=1)
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_serializer(self, *args, **kwargs):
        if self.action == 'password':
            return UpdatePasswordSerializer(*args, **kwargs)
        return self.serializer_class(*args, **kwargs)

    def update(self, request, pk):
        """
        个人信息修改
        1.User表更新
        -通过pk查询user对象
        -拿到传入的数据request。data, 反序列化
        -字段校验is_valid
        -更新
        2.UserDetail表更新
        -判断该用户是否有详情
        -有，获取，无，创建
        -字段校验
        -更新
        :param request:
        :param pk: 用户id
        :return:
        """
        # 1.User表更新
        #   -通过pk查询user对象
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        #   -拿到传入的数据request。data, 反序列化
        user_serializer = self.get_serializer(user, data=request.data)
        #         -字段校验is_valid
        user_serializer.is_valid(raise_exception=True)
        #         -更新
        user_serializer.save()
        #         2.UserDetail表更新
        user_detail = request.data['userdetail']
        #         -判断该用户是否有详情
        if hasattr(user, 'userdetail'):
            #         -有，获取，无，创建
            user_detail_serializer = UserDetailSerializer(user.userdetail, data=user_detail)
        else:
            user_detail_serializer = UserDetailSerializer(data=user_detail)
            #         -字段校验
        user_detail_serializer.is_valid(raise_exception=True)
        #         -更新
        user_detail_serializer.save()

        # 构造返回的数据结构
        user_serializer.data['userdetail'] = user_detail_serializer.data
        return Response(user_serializer.data)

    @action(methods=['put'], detail=True)
    def password(self, request, pk):
        """
        1.根据pk查到用户对象
        2.拿到传入的数据，request.data
        3.字段校验
        4.判断提交的旧密码和数据库里存放的是够一致
            -正确，修改
            -错误，返回状态码，终止程序

        :param request:
        :param pk:
        :return:
        """
        # 1.根据pk查到用户对象
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
            #         2.拿到传入的数据，request.data
        password = request.data['password']
        new_password = request.data['new_password']
        #         3.字段校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        #         4.判断提交的旧密码和数据库里存放的是够一致
        if user.check_password(password):
            #             -正确，修改
            user.set_password(new_password)
            user.save()
            return Response({'msg': '修改成功'})
        #             -错误，返回状态码，终止程序
        return Response(status=HTTP_400_BAD_REQUEST)

    @action(methods=['post'], detail=True)
    def avatar(self, request, pk):
        """
        头像上传功能
        1.根据pk获取用户对象
        2.获取传入的信息（头像图片文件：request。FILES）
        3.校验（文件数据和格式）
        4.上传到FastDFS
        5.将返回的地址存储到mysql数据库（详情表）
        6.返回响应
        :param request:
        :param pk:
        :return:
        """
        # 1.根据pk获取用户对象
        try:
            user = User.objects.get(pk=pk)
        except User.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 2.获取传入的信息（头像图片文件：request。FILES）
        files = request.FILES.get('file')
        # 3.校验（文件数据和格式）
        if not files or files.content_type not in ('image/jpeg', 'image/png', 'image/gif', 'image/jpg'):
            return Response(status=HTTP_400_BAD_REQUEST)
        # 4.上传到FastDFS
        try:  # 1.jpg
            image_ext_name = files.name.split('.')[-1]
        except Exception as e:
            image_ext_name = 'png'

        try:
            res = client.upload_by_buffer(files.read(), file_ext_name=image_ext_name)
        except Exception as e:
            logger.error(f'图片上传错误：{e}')
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
        else:
            if res.get('Status') != 'Upload successed.':
                return Response({'msg': '图片上传失败，请稍后重试或联系管理员'}, status=HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                # 5.将返回的地址存储到mysql数据库（详情表）
                image_url = FASTDFS_SERVER_DOMAIN + res.get('Remote file_id').decode()
                if hasattr(user, 'userdetail'):  # 判断用户是否有详情
                    # 有，修改
                    user_detail = user.userdetail
                    user_detail.avatar = image_url
                    user_detail.save()
                else:
                    # 无，创建
                    UserDetail.objects.create(avatar=image_url, user=user)
                # 6.返回响应
                return Response({'data': image_url})


class AreaViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
    # queryset = Area.objects.filter(parent=None)  # 查询省份
    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)  # 查询省份
        else:
            return Area.objects.all()  # 查询省份下所有城市

    # serializer_class = AreaSerializer
    def get_serializer_class(self):
        if self.action == 'list':
            return AreaSerializer  # 查询省份
        else:
            return ParentSerializer  # 查询省份下所有城市

    permission_classes = [IsAuthenticated]


class AddressViewSet(ModelViewSet):
    # 查询集：当前登录用户，之鞥呢查询自己用户的地址
    def get_queryset(self):
        return self.request.user.address_set.filter(is_delete=False)

    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    @auto_user
    def create(self, request, *args, **kwargs):
        return CreateModelMixin.create(self, request, *args, **kwargs)

    @auto_user
    def update(self, request, *args, **kwargs):
        return UpdateModelMixin.update(self, request, *args, **kwargs)


